package pacBioSimple;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Entropy<T>
{
	protected List<T> alphabet = null;
	
	
	public Entropy(List<T> alphabet)
	{
		this.alphabet=alphabet;		
	}
	
	
	
	protected double entropy(List<Double>prob)
	{
		double sum=0;
		for(int i=0; i < prob.size();++i)
		{
			if(prob.get(i)!=0)
			sum+=prob.get(i)*(Math.log(prob.get(i))/Math.log(2));
		}
		sum*=-1;
		return sum;
	}
	
	
	public double calcEntropyDimer(String string)
	{
		double entropy_1=entropy(calcEntropyString(string));
		double entropy_2=entropy(calcEntropyString(string.substring(1)));
		return (entropy_1+entropy_2)/2;
		
	}
	protected List<Double>calcEntropyString(String string)
	{
		List<Double>prob = new ArrayList<Double>();
		Map<String, Integer> distr = new HashMap<String, Integer>();
		for(int i=0; i <=string.length()-2;i+=2)
		{
			if(!distr.containsKey(string.substring(i,i+2)))
			{
				distr.put(new String(string.substring(i,i+2)),1);
			}
			else
			{
				distr.put(string.substring(i,i+2),distr.get(string.substring(i,i+2))+1);
			}
		}
		for(int i=0; i < this.alphabet.size();++i)
		{
			if(distr.get(this.alphabet.get(i).toString())==null)
			{
				prob.add(0.0);
			}
			else
			prob.add((double)distr.get(this.alphabet.get(i).toString())/(double)string.length()*2.0);
		}
		return prob;
	}
	
	protected List<Double> calcProb(String string)
	{
		List<Double>prob = new ArrayList<Double>();
		Map<Character, Integer> distr = new HashMap<Character, Integer>();
		for(int i=0; i <string.length();++i)
		{
			if(!distr.containsKey(string.charAt(i)))
			{
				distr.put(string.charAt(i),1);
			}
			else
			{
				distr.put(string.charAt(i),distr.get(string.charAt(i))+1);
			}
		}
		for(int i=0; i < this.alphabet.size();++i)
		{
			if(distr.get(this.alphabet.get(i))==null)
			{
				prob.add(0.0);
			}
			else
			prob.add((double)distr.get(this.alphabet.get(i))/(double)string.length());
		}
		return prob;
	}
	
	public double calcMaxEntropy()
	{
		List<Double> prob = new ArrayList<Double>();
		double alphabetLength = this.alphabet.size();
		for(int i=0; i<alphabetLength;++i)
		{
			prob.add(1.0/alphabetLength);
		}
		return entropy(prob);
	}
	
	
	public double calcEntropy(String string)
	{
		return entropy(calcProb(string));
	}
}
